package com.example.spring_gobang.game;

import com.example.spring_gobang.messgae.GameRequest;
import com.example.spring_gobang.messgae.GameResponse;
import com.example.spring_gobang.model.UserInfo;
import com.example.spring_gobang.service.UserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import com.example.spring_gobang.SpringGobangApplication;
import java.io.IOException;
import java.util.UUID;
@Data
public class Room {
    private String roomId;//设置为字符串便于生成唯一值
    private UserInfo userInfo1;//玩家1
    private UserInfo userInfo2;//玩家2
    //模拟棋盘 0相当于该位置未落子
    //1表示玩家1的落子位置 2表示玩家2的落子位置
    private int[][] board = new int[15][15];
    //先手方的用户Id
    private int whiteUser;
    private ObjectMapper objectMapper;
    //@Autowired
    private OnlineUserManage onlineUserManage;
    //@Autowired
    private RoomManager manager;
    private UserService userService;
    //记录当前客户端发来的落子请求
    //完成落子请求后 判定有没有胜负关系出现
    //将响应发回给两个客户端
    public void putChess(String jsonString) throws IOException {
        //1.确定落子位置 先把前端发来的JSON格式的字符串进行转换
        GameRequest request = objectMapper.readValue(jsonString,GameRequest.class);
        GameResponse response = new GameResponse();
        //这个棋子是玩家1还是玩家2
        int chess = request.getUserId() == userInfo1.getUserId() ? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        //这个棋子是否有棋子
        if (board[row][col] != 0){
            System.out.println("这个位置已经有子了");
            return;
        }
        //该位置没有棋子
        board[row][col] = chess;
        //2.打印出来棋盘信息
        printChess();
        //3.判定胜负关系
        int winer = checkWinner(row,col,chess);
        //4.判定完胜负关系给所有的客户端发送这个响应
        response.setCol(col);
        response.setRow(row);
        response.setWinner(winer);
        response.setUserId(request.getUserId());
        response.setMessage("putChess");
        //要想给所有用户进行消息推送
        //则要获得他们所有的一个session
        WebSocketSession session1 = onlineUserManage.getRoomById(userInfo1.getUserId());
        WebSocketSession session2 = onlineUserManage.getRoomById(userInfo2.getUserId());
        if (session1 == null){
            //如果玩家1下线 则直接判定玩家2赢
            response.setWinner(userInfo2.getUserId());
            System.out.println("玩家1下线");
        }
        if (session2 == null){
            //如果玩家2下线 则直接判定玩家1赢
            response.setWinner(userInfo1.getUserId());
            System.out.println("玩家2下线");
        }
        //将响应转化成JSON格式传输给前端
        if (session1 != null){
           session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        if (session2 != null){
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
        //如果本次落子响应结束后 玩家1和玩家2的胜负关系已经定了 则直接销毁房间就可以了
        if (response.getWinner() != 0){
            System.out.println("游戏结束 房间Id为" + roomId + "获胜方为"+ (response.getWinner() == userInfo1.getUserId() ? userInfo1.getUsername() : userInfo2.getUsername()));
            //此时胜负已分 进行修改
            int winnerrId = response.getWinner();
            int loserId = (response.getWinner() == userInfo1.getUserId()) ? userInfo2.getUserId() : userInfo1.getUserId();
            userService.userWin(winnerrId);
            userService.userLose(loserId);
            //销毁这个房间
            manager.remove(roomId,userInfo1.getUserId(),userInfo2.getUserId());
        }
    }

    private int checkWinner(int row, int col, int chess) {
// 1. 检查所有的行
        //    先遍历这五种情况
        for (int c = col - 4; c <= col; c++) {
            // 针对其中的一种情况, 来判定这五个子是不是连在一起了~
            // 不光是这五个子得连着, 而且还得和玩家落的子是一样~~ (才算是获胜)
            try {
                if (board[row][c] == chess
                        && board[row][c + 1] == chess
                        && board[row][c + 2] == chess
                        && board[row][c + 3] == chess
                        && board[row][c + 4] == chess) {
                    // 构成了五子连珠! 胜负已分!
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                // 如果出现数组下标越界的情况, 就在这里直接忽略这个异常.
                continue;
            }
        }

        // 2. 检查所有列
        for (int r = row - 4; r <= row; r++) {
            try {
                if (board[r][col] == chess
                        && board[r + 1][col] == chess
                        && board[r + 2][col] == chess
                        && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 3. 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if (board[r][c] == chess
                        && board[r + 1][c + 1] == chess
                        && board[r + 2][c + 2] == chess
                        && board[r + 3][c + 3] == chess
                        && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 4. 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if (board[r][c] == chess
                        && board[r + 1][c - 1] == chess
                        && board[r + 2][c - 2] == chess
                        && board[r + 3][c - 3] == chess
                        && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? userInfo1.getUserId() : userInfo2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 胜负未分, 就直接返回 0
        return 0;
    }

    private void printChess() {
        // 打印出棋盘
        System.out.println("[打印棋盘信息] " + roomId);
        System.out.println("=====================================================================");
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15L; j++) {
                // 针对一行之内的若干列, 不要打印换行
                System.out.print(board[i][j] + " ");
            }
            // 每次遍历完一行之后, 再打印换行.
            System.out.println();
        }
        System.out.println("=====================================================================");
    }
    public Room() {
        // 构造 Room 的时候生成一个唯一的字符串表示房间 id.
        // 使用 UUID 来作为房间 id
        roomId = UUID.randomUUID().toString();
        // 通过入口类中记录的 context 来手动获取到前面的 RoomManager 和 OnlineUserManager
        onlineUserManage = SpringGobangApplication.context.getBean(OnlineUserManage.class);
        manager = SpringGobangApplication.context.getBean(RoomManager.class);
        objectMapper = SpringGobangApplication.context.getBean(ObjectMapper.class);
        userService = SpringGobangApplication.context.getBean(UserService.class);
    }
}
